package com.titan.single.util;


import org.anarres.lzo.*;
import org.xerial.snappy.Snappy;
import com.github.luben.zstd.Zstd;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * 压缩工具类
 */
public class CompressUtil {

    /********************************** Snappy  ***************************************/

    public static byte[] compressSnappy( Object bt ) throws IOException{
        return  Snappy.compress((byte[])bt);
    }

    public static Object unCompressSnappy( Object bt) throws IOException{
        if(null == bt)
        { return  null ;}
        return  Snappy.uncompressString((byte[])bt);
    }

    /*********************************** giz **********************************************/

    /**
     * @param bt
     * @return
     * @description 将byte 数组压缩
     */
    public static byte[] compressGIP( Object bt ) {
        //将byte数据读入文件流
        ByteArrayOutputStream bos = null;
        GZIPOutputStream gzipos = null;
        try {
            bos = new ByteArrayOutputStream();
            gzipos = new GZIPOutputStream(bos);
            gzipos.write(serialize(bt));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeStream(gzipos);
            closeStream(bos);
        }
        return bos.toByteArray();
    }


    /**
     * @param bt
     * @return
     * @description 解压缩byte数组
     */
    public static Object unCompressGIP(Object bt) {
        if (null == bt) {
            return null;
        }

        ByteArrayInputStream byteArrayIn = null;
        GZIPInputStream gzipIn = null;
        ByteArrayOutputStream byteAos = null;

        try {
            byteArrayIn = new ByteArrayInputStream((byte[]) bt);
            gzipIn = new GZIPInputStream(byteArrayIn);
            byteAos = new ByteArrayOutputStream();
            byte[] b = new byte[4096];
            int temp = -1;
            while ((temp = gzipIn.read(b)) > 0) {
                byteAos.write(b, 0, temp);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            closeStream(byteAos);
            closeStream(gzipIn);
            closeStream(byteArrayIn);
        }

        // 添加空值检查，防止 unserialize 返回 null
        Object unserializedData = unserialize(byteAos.toByteArray());
        if (unserializedData == null) {
            return null;
        }

        return new String((byte[]) unserializedData);
    }


    /*********************************** LZO **********************************************/

    public static byte[] compressLZO( Object bt)   {
        ByteArrayOutputStream os = null ;
        LzoOutputStream cs = null;
        byte[] lzoByte = null ;
        try {
            LzoCompressor compressor = LzoLibrary.getInstance().newCompressor(
                LzoAlgorithm.LZO1X, null);
            os = new ByteArrayOutputStream();
            cs = new LzoOutputStream(os, compressor);
            cs.write((byte[])bt);
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            CompressUtil.closeStream(cs);
            CompressUtil.closeStream(os);
        }
        return  os.toByteArray();
    }

    public static Object uncompressLZO( Object bt)  {

        if(null == bt)
        { return  null ;}
        ByteArrayOutputStream baos = null ;
        ByteArrayInputStream is = null ;
        LzoInputStream us = null ;

        try {
            LzoDecompressor decompressor = LzoLibrary.getInstance()
                .newDecompressor(LzoAlgorithm.LZO1X, null);
            baos = new ByteArrayOutputStream();
            is = new ByteArrayInputStream((byte[]) bt);
            us = new LzoInputStream(is, decompressor);
            int count;
            byte[] buffer = new byte[4096];
            while ((count = us.read(buffer)) > 0) {
                baos.write(buffer, 0, count);
            }
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            CompressUtil.closeStream(us);
            CompressUtil.closeStream(is);
            CompressUtil.closeStream(baos);
        }

        return baos.toString();
    }


    /*********************************** zstd **********************************************/

    // 压缩
    public static byte[] compressZSTD(Object bt) {
        byte[] data = (byte[])bt;
        return Zstd.compress(data,6);
    }

    // 解压
    public static Object uncompressZSTD(Object bt) {
        byte[] compressedData = (byte[])bt;
        long originalSize = Zstd.decompressedSize(compressedData);
        if (originalSize == -1) {
            throw new RuntimeException("无法获取原始大小，可能数据损坏");
        }
        // 2. 解压
        byte[] uncompressed = Zstd.decompress(compressedData, (int) originalSize);

        // 3. 按 UTF-8 转成字符串
        return  new String(uncompressed, StandardCharsets.UTF_8);
    }


    /********************************** 对象 与 byte ***************************************/

    //序列化
    public static byte[] serialize(Object object) {
        ByteArrayOutputStream baos = null;
        ObjectOutputStream oos = null;
        try {
            // 序列化
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            byte[] bytes = baos.toByteArray();

            return bytes;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }finally {
            closeStream(oos);
            closeStream(baos);
        }
    }

    //返序列化
    public static Object unserialize(byte[] bytes) {
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null ;
        try {
            // 反序列化
            bais = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bais);
            return ois.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }finally {
            closeStream(ois);
            closeStream(bais);
        }
    }


    /**
     * @param oStream
     * @description 关闭数据流
     */
    public static void closeStream(Closeable oStream) {
        if (null != oStream) {
            try {
                oStream.close();
            } catch (IOException e) {
                oStream = null;//赋值为null,等待垃圾回收
                e.printStackTrace();
            }
        }
    }

}